#########################################################################################
#Funo coremicrobiome() - Anlise do Core Microbime para estudos de Ecologia Microbiana#
#########################################################################################

coremicrobiome = function(otu_table, numbercateg=NULL, namecateg=NULL)#O arquivo otu_table poder conter, ou no, informaes taxnomicas. 
                                                                      #O usurio dever indicar o nmero de categorias (p.ex.:numbercateg=4) (limitado a quatro) e o                                                                          #identificador nico das categorias anlisadas (p.ex.:namecateg=c("Cnt", "Lag", "Oce", "Esg").
{
  check=rep(NA, ncol(otu_table))#Crie repeties de NAs de acordo com o nmero de colunas do seu data.frame.
  for(i in 1:ncol(otu_table))#Guarde o nmero de colunas dentro de i.
  {
    check[i]=is.numeric(otu_table[,i])#Verifica se os valores das linhas do arquivo otu_table  nmerico. Numrico: TRUE. No numrico: FALSE.
  }
  if (sum(check)!=ncol(otu_table))#Se a soma dos elementos de check no for igual (!=) ao nmero de colunas do seu data.frame, significa que seu arquivo possui                                           #uma coluna com informaes taxonomicas, para proseguirmos, usaremos um data.frame sem esta coluna.
  {
    otu=otu_table[,1:ncol(otu_table)-1]#O objeto otu guardar as informaes do seu data.frame, exceto a ltima coluna. 
  } else                               #Caso a condio if no for verdadeira, ou seja, caso seu data.frame no contenha informaes taxonomicas, seguiremos com o
                                       #objeto "otu". 
  {
    otu=otu_table                      #Objeto "otu" contendo as informaes do seu data.frame sem informaes taxonomicas.
  }
  check2=rep(NA, ncol(otu))#Crie repeties de NAs de acordo com o nmero de colunas do seu data.frame.
  for(i in 1:ncol(otu))#Guarde o nmero de colunas dentro de i.
  {
    check2[i]=is.numeric(otu[,1])#Verifica se os valores das linhas do objeto otu  nmerico. Numrico: TRUE. No numrico: FALSE.
  }
  if (sum(check2)==ncol(otu))#Se a soma (sum) dos elementos de check2 for igual (==) ao nmero de colunas do data.frame.
  {
    otu2=otu                 #otu2 permanecer igual ao objeto otu. 
  } else                     #Caso a condio if no for verdadeira o comando ir parar (stop) e enviar a mensagem informando ao usurio que o arquivo deve 
                             #seguir o formato classico do Qiime para uma Otu Table.
  {
    stop("Input data must be in Qiime Classic Otu Table format (with or without taxonomy annotations) ===> https://www.drive5.com/usearch/manual/qiime_classic.html")
  }
  if("plyr" %in% rownames(installed.packages()) == FALSE)#Se o pacote "plyr" no estiver instalado...
                                                         #plyr  um pacote do R que permite a fragmentao e a juno de diferentes pores dos seus dados. 
  {
    stop("The 'plyr' package is required. Please, install it before continuing")#Se o pacote "plyr" no estiver instalado, o comando ir parar (stop) e enviar
                                                                                #uma mensagem pedindo para o usurio instalar o pacote para continuar.  
  } else
  {
    library("plyr")#Se o pacote j estiver instalado, ele ser "chamado" pelo comando library("plyr"). 
  }
  if("VennDiagram" %in% rownames(installed.packages()) == FALSE)#Se o pacote "VennDiagram" no estiver instalado...
                                                                #O pacote "VennDiagram"  utilizado para criao de diagramas do tipo Venn.
  {
    stop("The 'VennDiagram' package is required. Please, install it before continuing")#Se o pacote "VennDiagram" no estive instalado, o comando ir parar (stop) e
                                                                                       #enviar uma mensagem pedindo para o usurio instalar o pacote para continuar.
  } else
  {
    suppressPackageStartupMessages(library("VennDiagram"))#Se o pacote j estiver instalado, ele ser "chamado" pelo comando library("VennDiagram), alm de suprir as                                                             #mensagens de iniciao.
  }

  bin=as.data.frame((otu2>0)*1)#Com o comando otu2>0 convertemos o objeto otu2 para um objeto da classe logical, onde valores diferentes de zero se tornam TRUE e todos                                #os iguais a zero se tornam FALSE.
                               #Em vetores da classe logical, TRUE corresponde a 1 e FALSE corresponde a 0 em operaes matemticas. Sendo assim, se multiplicarmos
                               #todo o objeto lgico por 1, teremos um data.frame binrio.
                               #as.data.frame fora o arquivo a ser da classe data.frame.                               
                              
  if(is.null(numbercateg))#Pegar todas as colunas do arquivo de entrada e avaliar o core microbiome de todas elas. 
  {
    cor.01=subset(bin, apply(bin, 1, sum)==ncol(bin))#apply retorna um vetor, matriz ou uma lista obtidos aplicando uma funo aos dados. Neste caso, bin  o                                                                #data.frame, 1 indica que a operao ocorrer em linhas e a funo ser soma (sum). 
                                                     #cor.01: a soma das linhas deve ser igual ao nmero de colunas. 

    cor=list("Quantitative"=nrow(cor.01), "Qualitative"=rownames(cor.01))#list: criao de uma lista.
                                                                         #Far uma lista com as informaes de nmero de linhas (nrow) e o nome de cada linha                                                                                    #(rownames) (OTU_ID) do objeto cor.01 que atenderam a exigncia anterior. 

    draw.single.venn(nrow(cor.01), category=deparse(substitute(x)), lty="blank", fill="green", alpha=0.5, cex=2.5, cat.cex=2.5)#draw.single.venn cria um diagrama de                                                                                                                                   #Venn com um nico conjunto.
                                                                                                                               #lty: Define o padro de trao da                                                                                                                                       #circunferncia do diagrama.
                                                                                                                               #fill: Define a cor de preenchimento.
                                                                                                                               #alpha: Transparncia do crculo.
                                                                                                                               #cex: Define o tamanho a rea.
                                                                                                                               #cat.cex: Define o tamanho do nome da                                                                                                                                   #categoria.
  } else if(numbercateg==1)#Se o nmero de categoria for igual a 1.
  {
    stopifnot(length(namecateg)==numbercateg)#Verifica os argumentos da funo. No caso se o tamanho dos identificadores nicos so iguais ao nmero de tratamento.
    cor.01=subset(bin, select=grepl(namecateg, names(bin)))#O objeto cor.01, baseado no objeto bin, guardar as informaes da sua categoria (no caso 1).

    cor.02=subset(cor.01, apply(cor.01, 1, sum)==ncol(cor.01))#cor.02: a soma das linhas do objeto cor.01 deve ser igual ao nmero de colunas do mesmo objeto.  
    cor=list("Quantitative"=nrow(cor.02), "Qualitative"=rownames(cor.02))#Far uma lista com as informaes de nmero de linhas (nrow) e o nome de cada linha                                                                                    #(rownames) (OTU_ID) do objeto cor.02. Sero as OTUs compartilhadas entre todas as suas                                                                                 #amostras do tratamento (core microbiome). 


    draw.single.venn(nrow(cor.02), category=namecateg, lty="blank", fill="green", alpha=0.5, cex=2, cat.cex=2)#draw.single.venn cria um diagrama de Venn com um nico                                                                                                                 #conjunto. A quantidade de OTUs pertencentes ao seu core                                                                                                                #microbiome. 
                                                                                                       
  } else if(numbercateg==2)#Se o nmero de categorias for igual a 2.
  {
    stopifnot(length(namecateg)==numbercateg)#Verifica os argumentos da funo. No caso, o tamanho dos identificadores nicos devem ser iguais ao nmero de tratamento.
    cor.01a=subset(bin, select=grepl(namecateg[1], names(bin)))#grepl utiliza expresses regulares para combinar padres, neste caso, combinar apenas os padres                                                                #encontrados no identificador nico 1 (namecateg[1]) do objeto bin. 
                                                               #O subset retornar a condio exigida. 
                                                               #O objeto cor.01a, baseado no objeto bin, guardar apenas as informaes do primeiro identificador                                                                #nico.  

    cor.02a=subset(cor.01a, apply(cor.01a, 1, sum)==ncol(cor.01a))#A soma das linhas do objeto cor.01a deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02a guardar a informao do core microbiome da primeira categoria.  
 
    cor.01b=subset(bin, select=grepl(namecateg[2], names(bin)))#O objeto cor.01b, baseado no objeto bin, guardar apenas as informaes do segundo identificador nico.

    cor.02b=subset(cor.01b, apply(cor.01b, 1, sum)==ncol(cor.01b))#A soma das linhas do objeto cor.01b deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02b guardar a informao do core microbiome da segunda categoria. 

    cor.03=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b)))#O objeto cor.03 ser o valor de sobreposio dos objetos cor.02a e cor.02b, criando uma lista                                                                          #com o nome das linhas que so comuns entre os dois objetos (OTU_ID). 

    cor.04=c(nrow(cor.02a), nrow(cor.02b), length(cor.03))#Concatena o nmero de linhas dos objetos cor.02a, cor.02b e o nmero de observaes do cor.03.

    names(cor.04)=c(namecateg[1], namecateg[2], paste0(namecateg[1], namecateg[2]))#names faz referncia a um objeto pelo nome, no caso, cor.04
                                                                                   #paste tem por objetivo concatenar uma sequncias de caracteres.

    cor.05=list(rownames(cor.02a), rownames(cor.02b), cor.03)#Criao de uma lista.
                                                             #rownames: nome de cada linha. 
                                                             #cor.05 guardar em uma lista o nome das linhas (OTU_ID) dos objetos cor.02a (namecateg1) e cor.02b                                                              #(namecateg2) e o valor de observao do cor.03 (sobreposio de cor.02a e cor.02b).                                             

    names(cor.05)=names(cor.04)#Obter ou definir os nomes dos objeto.

    cor=list("Quantitative"=cor.04, "Qualitative"=cor.05)#A informao  guardada na forma de lista.

    draw.pairwise.venn(nrow(cor.02a), nrow(cor.02b), length(cor.03), category=c(namecateg[1], namecateg[2]), lty="blank", fill=c("green", "deepskyblue"), alpha=0.5, cex=2, cat.cex=2)#draw.pairwise.vem cria um diagrama de Venn com dois conjuntos, no caso, com o nmero de linhas do objeto cor.02a e cor.02b e o valor de sobreposio                  #entre esses dois objetos.
 
   } else if(numbercateg==3)#Se o nmero de categorias for igual a 3.
  {
    stopifnot(length(namecateg)==numbercateg)#Verifica os argumentos da funo. No caso, o tamanho dos identificadores nicos devem ser iguais ao nmero de tratamento.
    cor.01a=subset(bin, select=grepl(namecateg[1], names(bin)))#O objeto cor.01a, baseado no objeto bin, guardar apenas as informaes do primeiro identificador                                                                #nico. 
    cor.02a=subset(cor.01a, apply(cor.01a, 1, sum)==ncol(cor.01a))#A soma das linhas do objeto cor.01a deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02a guardar a informao do core microbiome da primeira categoria. 
 
    cor.01b=subset(bin, select=grepl(namecateg[2], names(bin)))#O objeto cor.01b, baseado no objeto bin, guardar apenas as informaes do primeiro identificador                                                                #nico.
    cor.02b=subset(cor.01b, apply(cor.01b, 1, sum)==ncol(cor.01b))#A soma das linhas do objeto cor.01b deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02b guardar a informao do core microbiome da segunda categoria. 

    cor.01c=subset(bin, select=grepl(namecateg[3], names(bin)))#O objeto cor.01c, baseado no objeto bin, guardar apenas as informaes do terceiro identificador                                                                #nico.
    cor.02c=subset(cor.01c, apply(cor.01c, 1, sum)==ncol(cor.01c))#A soma das linhas do objeto cor.01c deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02c guardar a informao do core microbiome da terceira categoria.


    cor.03=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02c)))#O ojbeto cor.03 ser o valor de sobreposio dos objetos cor.02a, cor.02b e                                                                                            #cor.02c, criando uma lista com o nome das linhas que so comuns entre os                                                                                               #trs objetos (OTU_ID).                                                                

    sobrep02ab=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b)))#Lista com o nome das linhas comuns aos ojbetos cor.02a e cor.02b.
    sobrep02bc=Reduce(intersect, list(rownames(cor.02b), rownames(cor.02c)))#Lista com o nome das linhas comuns aos objetos cor.02b e cor.02c.
    sobrep02ca=Reduce(intersect, list(rownames(cor.02c), rownames(cor.02a)))#Lista com o nome das linhas comuns aos objetos cor.02c e cor.02a.
    
    cor.04=c(nrow(cor.02a), nrow(cor.02b), nrow(cor.02c), length(cor.03))#Concatena o nmero de linhas dos objetos cor.02a, cor.02b, cor.02c e o nmero de observaes                                                                           #do cor.03.

    names(cor.04)=c(namecateg[1], namecateg[2], namecateg[3], paste0(namecateg[1], namecateg[2], namecateg[3]))#Concatena a sequncias de caracteres.

    cor.05=list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02c), cor.03)#cor.05 guardar em uma lista o nome das linhas (OTU_ID) dos objetos cor.02a                                                                                            #cor.02b, cor.02c e o valor de observao do cor.03 (sobreposio de                                                                                                    #cor.02a, cor.02b e cor.02c).

    names(cor.05)=names(cor.04)#Obter ou definir os nomes dos objeto.

    cor=list("Quantitative"=cor.04, "Qualitative"=cor.05)#A informao  guardada na forma de lista.

    draw.triple.venn(nrow(cor.02a), nrow(cor.02b), nrow(cor.02c), length(sobrep02ab),  length(sobrep02bc), length(sobrep02ca),length(cor.03), category=c(namecateg[1], namecateg[2], namecateg[3]), lty="blank", fill=c("blue", "red", "green"), alpha=0.5, cex=2, cat.cex=2)#draw.triple.vem cria um diagrama de Venn com trs conjuntos, no caso, com o nmero de linhas dos objetos cor.02a, cor.02b e cor.02c e os valores de sobreposio entre esses objetos.

  } else if(numbercateg==4)#Se o nmero de tratamento for igual a 4.
  {
    stopifnot(length(namecateg)==numbercateg)#Verifica os argumentos da funo. No caso, o tamanho dos identificadores nicos devem ser iguais ao nmero de tratamento.
    cor.01a=subset(bin, select=grepl(namecateg[1], names(bin)))#O objeto cor.01a, baseado no objeto bin, guardar apenas as informaes do primeiro identificador                                                                      #nico.
    cor.02a=subset(cor.01a, apply(cor.01a, 1, sum)==ncol(cor.01a))#A soma das linhas do objeto cor.01a deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02a guardar a informao do core microbiome da primeira categoria.
  
    cor.01b=subset(bin, select=grepl(namecateg[2], names(bin)))#O objeto cor.01b, baseado no objeto bin, guardar apenas as informaes do segundo identificador nico.
    cor.02b=subset(cor.01b, apply(cor.01b, 1, sum)==ncol(cor.01b))#A soma das linhas do objeto cor.01b deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02b guardar a informao do core microbiome da segunda categoria.

    cor.01c=subset(bin, select=grepl(namecateg[3], names(bin)))#O objeto cor.01c, baseado no objeto bin, guardar apenas as informaes do terceiro identificador                                                                #nico.
    cor.02c=subset(cor.01c, apply(cor.01c, 1, sum)==ncol(cor.01c))#A soma das linhas do objeto cor.01c deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02c guardar a informao do core microbiome da terceira categoria.

    cor.01d=subset(bin, select=grepl(namecateg[4], names(bin)))#O objeto cor.01d, baseado no objeto bin, guardar apenas as informaes do quarto identificador nico.
    cor.02d=subset(cor.01d, apply(cor.01d, 1, sum)==ncol(cor.01d))#A soma das linhas do objeto cor.01d deve ser igual ao nmero de colunas do mesmo objeto.
                                                                  #O objeto cor.02d guardar a informao do core microbiome da quarta categoria.

    cor.03=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02c), rownames(cor.02d)))#O objeto cor.03 ser o valor de sobreposio dos objetos                                                                                                                #cor.02a, cor.02b, cor.02c e cor.02d, criando uma lista                                                                                                                 #com o nome das linhas que so comuns entre os quatro                                                                                                                   #objetos (OTU_ID).
    
    sobrep02ab=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b)))#Lista com o nome das linhas comuns aos objetos cor.02a, cor.02b.
    sobrep02bc=Reduce(intersect, list(rownames(cor.02b), rownames(cor.02c)))#Lista com o nome das linhas comuns aos objetos cor.02b e cor.02c.
    sobrep02cd=Reduce(intersect, list(rownames(cor.02c), rownames(cor.02d)))#Lista com o nome das linhas comuns aos objetos cor.02c e cor.02d.
    sobrep02da=Reduce(intersect, list(rownames(cor.02d), rownames(cor.02a)))#Lista com o nome das linhas comuns aos objetos cor.02d e cor.02a.
    sobrep02ac=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02c)))#Lista com o nome das linhas comuns aos objetos cor.02a e cor.02c.
    sobrep02bd=Reduce(intersect, list(rownames(cor.02b), rownames(cor.02d)))#Lista com o nome das linhas comuns aos objetos cor.02b e cor.02d.
    sobrep02abc=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02c)))#Lista com o nome das linhas comuns aos objetos cor.02a, cor.02b e                                                                                                      #cor.02c.
    sobrep02bcd=Reduce(intersect, list(rownames(cor.02b), rownames(cor.02c), rownames(cor.02d)))#Lista com o nome das linhas comuns aos objetos cor.02b, cor.02c e                                                                                                      #cor.02d.
    sobrep02abd=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02d)))#Lista com o nome das linhas comuns aos objetos cor.02a, cor.02b e                                                                                                      #cor.02d.
    sobrep02acd=Reduce(intersect, list(rownames(cor.02a), rownames(cor.02c), rownames(cor.02d)))#Lista com o nome das linhas comuns aos objetos cor.02a, cor.02c e                                                                                                      #cor.02d.

    cor.04=c(nrow(cor.02a), nrow(cor.02b), nrow(cor.02c), nrow(cor.02d), length(cor.03))#Concatena o nmero de linhas dos objetos cor.02a, cor.02b, cor.02c, cor.02d e                                                                                          #o nmero de observaes do cor.03.

    names(cor.04)=c(namecateg[1], namecateg[2], namecateg[3], namecateg[4], paste0(namecateg[1], namecateg[2], namecateg[3], namecateg[4]))#Concatena a sequncias de                                                                                                                                            #caracteres.

    cor.05=list(rownames(cor.02a), rownames(cor.02b), rownames(cor.02c), rownames(cor.02d), cor.03)#cor.05 guardar em uma lista o nome das linhas (OTU_ID) dos objetos                                                                                                    #cor.02a, cor.02b, cor.02c, cor.02d e o valor de observao do                                                                                                          #cor.03 (sobreposio de cor.02a, cor.02b, cor.02c e cor.02d).
    names(cor.05)=names(cor.04)#Obter ou definir os nomes dos objeto.

    cor=list("Quantitative"=cor.04, "Qualitative"=cor.05)#A informao  guardada na forma de lista.

    draw.quad.venn(nrow(cor.02a), nrow(cor.02b), nrow(cor.02c), nrow(cor.02d), length(sobrep02ab), length(sobrep02bc), length(sobrep02cd), length(sobrep02da), length(sobrep02ac), length(sobrep02bd), length(sobrep02abc), length(sobrep02bcd), length(sobrep02abd), length(sobrep02acd), length(cor.03), category=c(namecateg[1], namecateg[2], namecateg[3], namecateg[4]), lty="blank", fill=c("blue", "red", "green", "purple"), alpha=0.5, cex=2, cat.cex=2)#draw.quad.vem cria um diagrama de Venn com quatro conjuntos, no caso, com o nmero de linhas dos objetos cor.02a, cor.02b, cor.02c e cor.02d e os valores de sobreposio entre esses objetos.
 }
    return(cor)#Retorna a lista com as informaes de core microbiome das categorias anlisadas. 
 }

############################################FIM DA FUNO##############################################

